package com.sz.admin.dept.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.sz.admin.dept.mapper.DeptMapper;
import com.sz.admin.dept.pojo.po.Dept;
import com.sz.admin.dept.pojo.dto.CompanyCreateDTO;
import com.sz.admin.dept.pojo.dto.CompanyListDTO;
import com.sz.admin.dept.pojo.dto.CompanyUpdateDTO;
import com.sz.admin.dept.pojo.dto.FleetCreateDTO;
import com.sz.admin.dept.pojo.dto.FleetListDTO;
import com.sz.admin.dept.pojo.dto.FleetUpdateDTO;
import com.sz.admin.dept.pojo.dto.LeaderDTO;
import com.sz.admin.dept.pojo.vo.CompanyVO;
import com.sz.admin.dept.pojo.vo.FleetVO;
import com.sz.admin.dept.service.DeptService;
import com.sz.admin.dept.service.DeptLeaderService;
import com.sz.core.common.entity.PageResult;
import com.sz.core.common.entity.SelectIdsDTO;
import com.sz.core.common.enums.CommonResponseEnum;
import com.sz.core.util.BeanCopyUtils;
import com.sz.core.util.PageUtils;
import com.sz.core.util.Utils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author sz-admin
 * @since 2025-10-20
 */
@Service
@RequiredArgsConstructor
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {

    private final DeptMapper deptMapper;
    private final DeptLeaderService deptLeaderService;

    @Transactional
    @Override
    public void createCompany(CompanyCreateDTO dto) {
        Dept dept = BeanCopyUtils.copy(dto, Dept.class);
        dept.setPid(0L);
        dept.setDeep(1);
        dept.setHasChildren("F");
        save(dept);
        
        // Handle leaders
        if (dto.getLeaders() != null && !dto.getLeaders().isEmpty()) {
            List<Long> leaderIds = dto.getLeaders().stream()
                .map(LeaderDTO::getId)
                .collect(Collectors.toList());
            deptLeaderService.syncLeader(dept.getId(), leaderIds);
        }
    }

    @Transactional
    @Override
    public void updateCompany(CompanyUpdateDTO dto) {
        Dept dept = BeanCopyUtils.copy(dto, Dept.class);
        dept.setPid(0L);
        dept.setDeep(1);
        
        // id有效性校验 - 如果记录不存在(count==0)，则抛出异常
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getId, dto.getId());
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) == 0);
        
        saveOrUpdate(dept);
        
        // Handle leaders
        if (dto.getLeaders() != null) {
            List<Long> leaderIds = dto.getLeaders().stream()
                .map(LeaderDTO::getId)
                .collect(Collectors.toList());
            deptLeaderService.syncLeader(dept.getId(), leaderIds);
        }
    }

    @Override
    public PageResult<CompanyVO> pageCompanies(CompanyListDTO dto) {
        QueryWrapper wrapper = buildCompanyQueryWrapper(dto);
        Page<CompanyVO> page = pageAs(PageUtils.getPage(dto), wrapper, CompanyVO.class);
        return PageUtils.getPageResult(page);
    }

    @Override
    public List<CompanyVO> listCompanies(CompanyListDTO dto) {
        QueryWrapper wrapper = buildCompanyQueryWrapper(dto);
        return listAs(wrapper, CompanyVO.class);
    }

    @Override
    public CompanyVO detailCompany(Object id) {
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getId, id)
            .eq(Dept::getPid, 0)
            .eq(Dept::getDeep, 1);
        Dept dept = getOne(wrapper);
        CommonResponseEnum.INVALID_ID.assertNull(dept);
        CompanyVO companyVO = BeanCopyUtils.copy(dept, CompanyVO.class);
        
        // Set leaders
        // TODO: Implement leader retrieval logic
        // companyVO.setLeaders(getLeadersForDept(dept.getId()));
        
        return companyVO;
    }

    @Override
    public void removeCompanies(SelectIdsDTO dto) {
        CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty());
        
        // Check if companies have fleets
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .where(Dept::getPid).in(dto.getIds())
            .and(Dept::getDeep).eq(2);
        long fleetCount = count(wrapper);
        
        if (fleetCount > 0) {
            throw new RuntimeException("无法删除公司，因为存在关联的车队");
        }
        
        removeByIds(dto.getIds());
    }

    @Transactional
    @Override
    public void createFleet(FleetCreateDTO dto) {
        // Check if company exists - 如果记录不存在(count==0)，则抛出异常
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getId, dto.getCompanyId())
            .eq(Dept::getPid, 0)
            .eq(Dept::getDeep, 1);
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) == 0);
        
        Dept dept = BeanCopyUtils.copy(dto, Dept.class);
        dept.setPid(dto.getCompanyId());
        dept.setDeep(2);
        dept.setHasChildren("F");
        save(dept);
        
        // Handle leaders
        if (dto.getLeaders() != null && !dto.getLeaders().isEmpty()) {
            List<Long> leaderIds = dto.getLeaders().stream()
                .map(LeaderDTO::getId)
                .collect(Collectors.toList());
            deptLeaderService.syncLeader(dept.getId(), leaderIds);
        }
        
        // Update company to hasChildren = "T"
        Dept company = getById(dto.getCompanyId());
        if (company != null) {
            company.setHasChildren("T");
            updateById(company);
        }
    }

    @Transactional
    @Override
    public void updateFleet(FleetUpdateDTO dto) {
        // Check if fleet exists - 如果记录不存在(count==0)，则抛出异常
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getId, dto.getId());
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) == 0);
        
        // Check if company exists - 如果记录不存在(count==0)，则抛出异常
        wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getId, dto.getCompanyId())
            .eq(Dept::getPid, 0)
            .eq(Dept::getDeep, 1);
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) == 0);
        
        Dept dept = BeanCopyUtils.copy(dto, Dept.class);
        dept.setPid(dto.getCompanyId());
        dept.setDeep(2);
        saveOrUpdate(dept);
        
        // Handle leaders
        if (dto.getLeaders() != null) {
            List<Long> leaderIds = dto.getLeaders().stream()
                .map(LeaderDTO::getId)
                .collect(Collectors.toList());
            deptLeaderService.syncLeader(dept.getId(), leaderIds);
        }
        
        // Update company to hasChildren = "T"
        Dept company = getById(dto.getCompanyId());
        if (company != null) {
            company.setHasChildren("T");
            updateById(company);
        }
    }

    @Override
    public PageResult<FleetVO> pageFleets(FleetListDTO dto) {
        QueryWrapper wrapper = buildFleetQueryWrapper(dto);
        Page<FleetVO> page = pageAs(PageUtils.getPage(dto), wrapper, FleetVO.class);
        return PageUtils.getPageResult(page);
    }

    @Override
    public List<FleetVO> listFleets(FleetListDTO dto) {
        QueryWrapper wrapper = buildFleetQueryWrapper(dto);
        return listAs(wrapper, FleetVO.class);
    }

    @Override
    public FleetVO detailFleet(Object id) {
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getId, id)
            .ne(Dept::getPid, 0)
            .eq(Dept::getDeep, 2);
        Dept dept = getOne(wrapper);
        CommonResponseEnum.INVALID_ID.assertNull(dept);
        FleetVO fleetVO = BeanCopyUtils.copy(dept, FleetVO.class);
        fleetVO.setCompanyId(dept.getPid());
        
        // Set leaders
        // TODO: Implement leader retrieval logic
        // fleetVO.setLeaders(getLeadersForDept(dept.getId()));
        
        return fleetVO;
    }

    @Override
    public void removeFleets(SelectIdsDTO dto) {
        CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty());
        removeByIds(dto.getIds());
    }

    private QueryWrapper buildCompanyQueryWrapper(CompanyListDTO dto) {
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .eq(Dept::getPid, 0)
            .eq(Dept::getDeep, 1);
            
        if (Utils.isNotNull(dto.getName())) {
            wrapper.like(Dept::getName, dto.getName());
        }
        if (Utils.isNotNull(dto.getSort())) {
            wrapper.eq(Dept::getSort, dto.getSort());
        }
        if (Utils.isNotNull(dto.getRemark())) {
            wrapper.like(Dept::getRemark, dto.getRemark());
        }
        if (Utils.isNotNull(dto.getScheduleId())) {
            wrapper.eq(Dept::getScheduleId, dto.getScheduleId());
        }
        
        return wrapper.orderBy(Dept::getSort).asc();
    }

    private QueryWrapper buildFleetQueryWrapper(FleetListDTO dto) {
        QueryWrapper wrapper = QueryWrapper.create()
            .from(Dept.class)
            .ne(Dept::getPid, 0)
            .eq(Dept::getDeep, 2);
            
        if (Utils.isNotNull(dto.getName())) {
            wrapper.like(Dept::getName, dto.getName());
        }
        if (Utils.isNotNull(dto.getCompanyId())) {
            wrapper.eq(Dept::getPid, dto.getCompanyId());
        }
        if (Utils.isNotNull(dto.getSort())) {
            wrapper.eq(Dept::getSort, dto.getSort());
        }
        if (Utils.isNotNull(dto.getRemark())) {
            wrapper.like(Dept::getRemark, dto.getRemark());
        }
        if (Utils.isNotNull(dto.getScheduleId())) {
            wrapper.eq(Dept::getScheduleId, dto.getScheduleId());
        }
        
        return wrapper.orderBy(Dept::getSort).asc();
    }
    
    // Method to get leaders for a department
    // private List<LeaderDTO> getLeadersForDept(Long deptId) {
    //     // TODO: Implement logic to retrieve leaders for a department
    //     return new ArrayList<>();
    // }
}